root/source3/printing/printing_db.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_print_db_byname
  2. release_print_db
  3. close_all_print_db
  4. get_printer_notify_pid_list

   1 /* 
   2    Unix SMB/Netbios implementation.
   3    Version 3.0
   4    printing backend routines
   5    Copyright (C) Andrew Tridgell 1992-2000
   6    Copyright (C) Jeremy Allison 2002
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include "printing.h"
  24 
  25 static struct tdb_print_db *print_db_head;
  26 
  27 /****************************************************************************
  28   Function to find or create the printer specific job tdb given a printername.
  29   Limits the number of tdb's open to MAX_PRINT_DBS_OPEN.
  30 ****************************************************************************/
  31 
  32 struct tdb_print_db *get_print_db_byname(const char *printername)
     /* [<][>][^][v][top][bottom][index][help] */
  33 {
  34         struct tdb_print_db *p = NULL, *last_entry = NULL;
  35         int num_open = 0;
  36         char *printdb_path = NULL;
  37         bool done_become_root = False;
  38 
  39         SMB_ASSERT(printername != NULL);
  40 
  41         for (p = print_db_head, last_entry = print_db_head; p; p = p->next) {
  42                 /* Ensure the list terminates... JRA. */
  43                 SMB_ASSERT(p->next != print_db_head);
  44 
  45                 if (p->tdb && strequal(p->printer_name, printername)) {
  46                         DLIST_PROMOTE(print_db_head, p);
  47                         p->ref_count++;
  48                         return p;
  49                 }
  50                 num_open++;
  51                 last_entry = p;
  52         }
  53 
  54         /* Not found. */
  55         if (num_open >= MAX_PRINT_DBS_OPEN) {
  56                 /* Try and recycle the last entry. */
  57                 if (print_db_head && last_entry) {
  58                         DLIST_PROMOTE(print_db_head, last_entry);
  59                 }
  60 
  61                 for (p = print_db_head; p; p = p->next) {
  62                         if (p->ref_count)
  63                                 continue;
  64                         if (p->tdb) {
  65                                 if (tdb_close(print_db_head->tdb)) {
  66                                         DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n",
  67                                                                 print_db_head->printer_name ));
  68                                         return NULL;
  69                                 }
  70                         }
  71                         p->tdb = NULL;
  72                         p->ref_count = 0;
  73                         memset(p->printer_name, '\0', sizeof(p->printer_name));
  74                         break;
  75                 }
  76                 if (p && print_db_head) {
  77                         DLIST_PROMOTE(print_db_head, p);
  78                         p = print_db_head;
  79                 }
  80         }
  81 
  82         if (!p) {
  83                 /* Create one. */
  84                 p = SMB_MALLOC_P(struct tdb_print_db);
  85                 if (!p) {
  86                         DEBUG(0,("get_print_db: malloc fail !\n"));
  87                         return NULL;
  88                 }
  89                 ZERO_STRUCTP(p);
  90                 DLIST_ADD(print_db_head, p);
  91         }
  92 
  93         if (asprintf(&printdb_path, "%s%s.tdb",
  94                                 cache_path("printing/"),
  95                                 printername) < 0) {
  96                 DLIST_REMOVE(print_db_head, p);
  97                 SAFE_FREE(p);
  98                 return NULL;
  99         }
 100 
 101         if (geteuid() != 0) {
 102                 become_root();
 103                 done_become_root = True;
 104         }
 105 
 106         p->tdb = tdb_open_log(printdb_path, 5000, TDB_DEFAULT, O_RDWR|O_CREAT, 
 107                 0600);
 108 
 109         if (done_become_root)
 110                 unbecome_root();
 111 
 112         if (!p->tdb) {
 113                 DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n",
 114                                         printdb_path ));
 115                 DLIST_REMOVE(print_db_head, p);
 116                 SAFE_FREE(printdb_path);
 117                 SAFE_FREE(p);
 118                 return NULL;
 119         }
 120         SAFE_FREE(printdb_path);
 121         fstrcpy(p->printer_name, printername);
 122         p->ref_count++;
 123         return p;
 124 }
 125 
 126 /***************************************************************************
 127  Remove a reference count.
 128 ****************************************************************************/
 129 
 130 void release_print_db( struct tdb_print_db *pdb)
     /* [<][>][^][v][top][bottom][index][help] */
 131 {
 132         pdb->ref_count--;
 133         SMB_ASSERT(pdb->ref_count >= 0);
 134 }
 135 
 136 /***************************************************************************
 137  Close all open print db entries.
 138 ****************************************************************************/
 139 
 140 void close_all_print_db(void)
     /* [<][>][^][v][top][bottom][index][help] */
 141 {
 142         struct tdb_print_db *p = NULL, *next_p = NULL;
 143 
 144         for (p = print_db_head; p; p = next_p) {
 145                 next_p = p->next;
 146 
 147                 if (p->tdb)
 148                         tdb_close(p->tdb);
 149                 DLIST_REMOVE(print_db_head, p);
 150                 ZERO_STRUCTP(p);
 151                 SAFE_FREE(p);
 152         }
 153 }
 154 
 155 
 156 /****************************************************************************
 157  Fetch and clean the pid_t record list for all pids interested in notify
 158  messages. data needs freeing on exit.
 159 ****************************************************************************/
 160 
 161 TDB_DATA get_printer_notify_pid_list(TDB_CONTEXT *tdb, const char *printer_name, bool cleanlist)
     /* [<][>][^][v][top][bottom][index][help] */
 162 {
 163         TDB_DATA data;
 164         size_t i;
 165 
 166         ZERO_STRUCT(data);
 167 
 168         data = tdb_fetch_bystring( tdb, NOTIFY_PID_LIST_KEY );
 169 
 170         if (!data.dptr) {
 171                 ZERO_STRUCT(data);
 172                 return data;
 173         }
 174 
 175         if (data.dsize % 8) {
 176                 DEBUG(0,("get_printer_notify_pid_list: Size of record for printer %s not a multiple of 8 !\n", printer_name ));
 177                 tdb_delete_bystring(tdb, NOTIFY_PID_LIST_KEY );
 178                 SAFE_FREE(data.dptr);
 179                 ZERO_STRUCT(data);
 180                 return data;
 181         }
 182 
 183         if (!cleanlist)
 184                 return data;
 185 
 186         /*
 187          * Weed out all dead entries.
 188          */
 189 
 190         for( i = 0; i < data.dsize; i += 8) {
 191                 pid_t pid = (pid_t)IVAL(data.dptr, i);
 192 
 193                 if (pid == sys_getpid())
 194                         continue;
 195 
 196                 /* Entry is dead if process doesn't exist or refcount is zero. */
 197 
 198                 while ((i < data.dsize) && ((IVAL(data.dptr, i + 4) == 0) || !process_exists_by_pid(pid))) {
 199 
 200                         /* Refcount == zero is a logic error and should never happen. */
 201                         if (IVAL(data.dptr, i + 4) == 0) {
 202                                 DEBUG(0,("get_printer_notify_pid_list: Refcount == 0 for pid = %u printer %s !\n",
 203                                                         (unsigned int)pid, printer_name ));
 204                         }
 205 
 206                         if (data.dsize - i > 8)
 207                                 memmove( &data.dptr[i], &data.dptr[i+8], data.dsize - i - 8);
 208                         data.dsize -= 8;
 209                 }
 210         }
 211 
 212         return data;
 213 }
 214 
 215 

/* [<][>][^][v][top][bottom][index][help] */